package com.fastwire.carriere.schedule;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import com.fastwire.carriere.common.constant.AppConstants;
import com.fastwire.carriere.common.constant.ScheduledTaskConstants;
import com.fastwire.carriere.common.util.CommonLogger;
import com.fastwire.carriere.common.util.DateUtil;
import com.fastwire.carriere.controller.impl.SchedularControllerImpl;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.schedule.entity.ScheduledTask;
import com.fastwire.carriere.schedule.runnable.RadDiscoveryThread;
import com.fastwire.carriere.schedule.runnable.U2kDiscoveryThread;
import com.fastwire.carriere.schedule.runnable.U2kProvisionThread;

// TODO: Auto-generated Javadoc
/**
 * The Class MultiTaskScheduler.
 */
public class MultiTaskScheduler {

	/** The scheduler. */
	private ScheduledExecutorService fScheduler;
	/** If invocations might overlap, specify more than a single thread. */
	private static final int NUM_THREADS = 1;

	/** The Constant DONT_INTERRUPT_IF_RUNNING. */
	private static final boolean DONT_INTERRUPT_IF_RUNNING = true;

	/** The task future map. */
	HashMap<Long, ScheduledFuture<?>> taskFutureMap = new HashMap<Long, ScheduledFuture<?>>();

	/** The instance. */
	private static MultiTaskScheduler instance;

	/**
	 * Instantiates a new multi task scheduler.
	 */
	private MultiTaskScheduler() {
		super();
		this.fScheduler = Executors.newScheduledThreadPool(NUM_THREADS);
		System.out.println("Creating insatnce of MultiTaskScheduler");
		CommonLogger.info(MultiTaskScheduler.class, "Creating insatnce of MultiTaskScheduler");
		
	}

	static {
		System.out.println("Calling static block of  MultiTaskScheduler");
		CommonLogger.info(MultiTaskScheduler.class, "Calling static block of  MultiTaskScheduler");
		if (instance == null) {

			instance = new MultiTaskScheduler();
			instance.init();
		}

	}

	/**
	 * Gets the single instance of MultiTaskScheduler.
	 * 
	 * @return single instance of MultiTaskScheduler
	 */
	public static synchronized MultiTaskScheduler getInstance() {

		if (instance == null) {

			instance = new MultiTaskScheduler();

		}

		return instance;
	}

	/**
	 * Start with fixed delay.
	 * 
	 * @param key
	 *            the key
	 * @param task
	 *            the task
	 * @param initialDelay
	 *            the initial delay
	 * @param delayBetweenRuns
	 *            the delay between runs
	 */
	public synchronized void startWithFixedDelay(Long key, Runnable task,
			long initialDelay, long delayBetweenRuns) {

		ScheduledFuture<?> taskFuture = taskFutureMap.get(key);
		if (taskFuture == null) {

			taskFuture = fScheduler.scheduleWithFixedDelay(task, initialDelay,
					delayBetweenRuns, TimeUnit.SECONDS);
			taskFutureMap.put(key, taskFuture);
		} else {

			System.out.println("There is a task running");

		}

	}

	public synchronized void startOneshotTask(Runnable task, long initialDelay) {

		fScheduler.schedule(task, initialDelay, TimeUnit.SECONDS);

	}

	/**
	 * Stop task.
	 * 
	 * @param key
	 *            the key
	 */
	public synchronized void stopTask(Long key) {

		ScheduledFuture<?> taskFuture = taskFutureMap.get(key);

		if (taskFuture != null) {

			taskFuture.cancel(DONT_INTERRUPT_IF_RUNNING);

			taskFuture = null;
			taskFutureMap.remove(key);
		}

	}

	/**
	 * Stop scheduler.
	 */
	public synchronized void stopScheduler() {
		if (fScheduler != null) {
			fScheduler.shutdown();
			fScheduler = null;
		}

	}

	public synchronized void init() {

		System.out.println("Start init schedular ");

		try {
			List<ScheduledTask> tasks = DAOFactory.getInstance()
					.getScheduledTask().getAllScheduledTasks();

			for (ScheduledTask task : tasks) {
				Date startDate = SchedularControllerImpl.getStartDate(task);
				long delayFromNow = Math.max(0,
						DateUtil.getDiffInSecs(startDate));
				Runnable thread = null;
				
				String taskType = task.getTaskType();

				// modified by Jun on 20120501
				// added the RAD discovery
				if (taskType.equals(ScheduledTaskConstants.TASK_U2000_PROVISION)) {
					thread = new U2kProvisionThread();
				} 
				else if(taskType.equals(AppConstants.DISCOVERY_TYPE_FULL) 
				       || taskType.equals(AppConstants.DISCOVERY_TYPE_SERVICE)
				       || taskType.equals(AppConstants.DISCOVERY_TYPE_ADHOC))
				{
					thread = new U2kDiscoveryThread(task.getTaskType(),
							task.getUserField());
				}
				else if (taskType.equals(AppConstants.DISCOVERY_RAD_FULL)
				        || taskType.equals(AppConstants.DISCOVERY_RAD_ADHOC) )
				{
				    thread = new RadDiscoveryThread(task.getTaskType(), task.getUserField());
				}
				else
				{
				    CommonLogger.info(this, "invalide task type.");
				}

				startWithFixedDelay(task.getOid(), thread, delayFromNow,
						task.getFixedRateInSec());
			}

		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
